package blms.system.manager;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import blms.system.exception.UnknownAttribute;
import blms.system.exception.restrictions.RestrictionException;
import blms.system.league.League;
import blms.system.user.User;
import blms.system.util.BLMSMessages;
import blms.system.util.ReflectionHelper;

/**
 * 
 *
 */
public class LeaguesManager {

	private Map<String, Set<Tuple>> leaguesTOTuple;
	private Map<String, List<League>> usersTOLeagues;
	
	/**
	 * 
	 */
	public LeaguesManager() {
		this.leaguesTOTuple= new HashMap<String, Set<Tuple>>();
		this.usersTOLeagues = new HashMap<String, List<League>>();
	}
	
	/**
	 * @param league
	 * @param user
	 * @param initialHandicap
	 * @throws RestrictionException
	 */
	public void join(League league, User user, int initialHandicap) throws RestrictionException {
		
		if (initialHandicap < 0) throw new RestrictionException(BLMSMessages.HANDICAP_CANT_BE_NEGATIVE_MESSAGE);
		this.join(league, user, initialHandicap, new Date());
	}
	
	/**
	 * @param league
	 * @param user
	 * @param initialHandicap
	 * @param initialDate
	 * @throws RestrictionException
	 */
	public void join(League league, User user, int initialHandicap, Date initialDate) throws RestrictionException {
		
		Tuple tuple = new Tuple(user, initialHandicap, initialDate);
		addNewTupleToLeague(league, tuple);
		addNewLeagueToUser(user, league);
	}
	
	/**
	 * @param league
	 * @param operator
	 * @throws RestrictionException
	 */
	public void join(League league, User operator) throws RestrictionException {
		this.join(league, operator, 0, new Date());
	}
	
	/**
	 * @param user
	 * @param league
	 * @param attribute
	 * @return
	 * @throws RestrictionException
	 * @throws UnknownAttribute
	 */
	public String getUserLeagueAttribute(User user, League league, String attribute) throws RestrictionException,
																								UnknownAttribute {
		
		if (!isLeagueMember(user, league)) throw new RestrictionException(BLMSMessages.USER_IS_NOT_LEAGUE_MEMBER_MESSAGE);
		
		for (Tuple tuple : this.leaguesTOTuple.get(league.getId())) {
			if (tuple.getUser().getID().equals(user.getID())) {
				return new ReflectionHelper().getAttribute(tuple, attribute);
			}
		}
		// bonito hein
		return "";
	}
	
	private void addNewLeagueToUser(User user, League league) {
		
		List<League> leagues;

		if ( (leagues = this.usersTOLeagues.get(user.getID())) == null ) {
			leagues = new LinkedList<League>();
			this.usersTOLeagues.put(user.getID(), leagues);
		} 

		leagues.add(league);
	}

	private void addNewTupleToLeague(League league, Tuple tuple) throws RestrictionException {
	
		Set<Tuple> tuples;
	
		if ( (tuples = this.leaguesTOTuple.get(league.getId())) == null ) {
			tuples = new HashSet<Tuple>();
			tuples.add(tuple);
			this.leaguesTOTuple.put(league.getId(), tuples);
		} else {
			for (Tuple t : tuples) {//refactor
				if (t.getUser().equals(tuple.getUser())) throw new RestrictionException(BLMSMessages.USER_IS_ALREADY_A_MEMBER_MESSAGE);
			}
			tuples.add(tuple);
		}
	}

	/**
	 * @param league
	 * @return
	 */
	public Collection<User> getLeagueMembers(League league) {
		
		Collection<User> members = new HashSet<User>();
		
		for (Tuple tuple: this.leaguesTOTuple.get(league.getId()) ) {
			members.add(tuple.getUser());//rapaz, se Users continuar mutável vai dar em merda
		}
		
		return members;
	}

	/**
	 * @param user
	 * @return
	 */
	public Collection<League> getPlayerLeagues(User user) {
		
		return (this.usersTOLeagues.get(user.getID()) == null) ? new LinkedList<League>() 
																	: this.usersTOLeagues.get(user.getID());
	}

	/**
	 * @param user
	 * @param league
	 * @return
	 */
	public boolean isLeagueMember(User user, League league) {
		
		if (league.getOperator().equals(user)) return true;
		
		if (this.leaguesTOTuple.get(league.getId()) == null) {
			return false;
		}
		
		for (Tuple tuple : this.leaguesTOTuple.get(league.getId())) {
			if (tuple.getUser().getID().equals(user.getID())) return true;
		}
		
		return false;
	}
	
	/**
	 * @param user
	 * @param league
	 * @throws RestrictionException
	 */
	public void leaveLeague(User user, League league) throws RestrictionException {
		
		if (!isLeagueMember(user, league)) throw new RestrictionException(BLMSMessages.USER_IS_NOT_LEAGUE_MEMBER_MESSAGE);
		
		if (league.getOperator().equals(user)) throw new RestrictionException(BLMSMessages.OPERATOR_CAN_NOT_LEAVE_LEAGUE);
		
		List<League> leagues = this.usersTOLeagues.get(user.getID());
		leagues.remove(league);
		
		Iterator<Tuple> it = this.leaguesTOTuple.get(league.getId()).iterator();
		Tuple tuple;
		while (it.hasNext()) {
			tuple = it.next();
			if (tuple.getUser().equals(user)) {
				it.remove();
				return;
			}
		}
	}

}
